/**
@author		Jong Min, Lee
@date		  10/01/2014
@breif		dicom series class

copyright(c) Tae Young Soft. All right reserved. 2014
*/
#include "stdafx.h"
#include "Taurus_DcmData/DcmSeries.h"
#include "Taurus_Util/Errors.h"
#include "Taurus_DcmData/DcmInstance.h"
#include "Taurus_DcmData/ISeriesInfo.h"

CDcmSeries::CDcmSeries()
{
  init();
}

CDcmSeries::~CDcmSeries()
{
  destroy();
}

BOOL CDcmSeries::isNoneImage() const
{
  BOOL isNoneImage = FALSE;

  if(m_theModality == _T("PR") || m_theModality == _T("SR"))
  {
    isNoneImage = TRUE;
  }
  else if(m_theModality.Find(_T("SR")) >= 0)
  {
    isNoneImage = FALSE;
    unsigned int numInstance = getNumInstances();
    for(unsigned i = 0; i < numInstance; ++i)
    {
      const CDcmInstance* ii = getInstance(i);

      CString sopClassUID = ii->getSOPClassUID();
      if(sopClassUID == _T("1.2.840.10008.5.1.4.1.1.4.2") ||     // Spectroscopy
         sopClassUID == _T("1.2.840.10008.5.1.4.1.1.88.11") ||   // basic text SR
         sopClassUID == _T("1.2.840.10008.5.1.4.1.1.88.22") ||   // Enhanced SR
         sopClassUID == _T("1.2.840.10008.5.1.4.1.1.88.33") ||   // Comprehensive SR
         sopClassUID == _T("1.2.840.10008.5.1.4.1.1.88.50") ||   // Mammography CAD SR
         sopClassUID == _T("1.2.840.10008.5.1.4.1.1.88.65") ||   // Chest CAD SR
         sopClassUID == _T("1.2.840.10008.5.1.4.1.1.88.59"))   // Key object selection DOC
      {
        isNoneImage = TRUE;
        break;
      }
    }
  }
  else if(m_theModality == _T("ECG"))
  {
    isNoneImage = FALSE;
    unsigned numInstances = getNumInstances();
    for(unsigned i = 0; i < numInstances; ++i)
    {
      const CDcmInstance* ii = getInstance(i);

      CString sopClassUID = ii->getSOPClassUID();
      if(sopClassUID == _T("1.2.840.10008.5.1.4.1.1.9.1.1") || //12-lead
         sopClassUID == _T("1.2.840.10008.5.1.4.1.1.9.2.1") || //HemodynamicWaveformStorage
         sopClassUID == _T("1.2.840.10008.5.1.4.1.1.9.1.2")) //General ECG Waveform Storage
      {
        isNoneImage = TRUE;
        break;
      }
    }
  }

  return isNoneImage;
}

CDcmInstance* CDcmSeries::getInstance(const unsigned int index)
{
  if(index >= m_theInstances.size()) return nullptr;
  return m_theInstances[index];
}

const CDcmInstance* CDcmSeries::getInstance(const unsigned int index) const
{
  if(index >= m_theInstances.size()) return nullptr;
  return m_theInstances[index];
}

DWORD CDcmSeries::addInstance(CDcmInstance* instance)
{
  if(instance == nullptr) return ERROR_INVALID_PARAMETER;

  _TRY_BEGIN
  m_theInstances.push_back(instance);
  _CATCH_ALL
  return ERROR_NOT_ENOUGH_MEMORY;
  _CATCH_END

  instance->setParent(this);
  return ERROR_SUCCESS;
}

CDcmInstance* CDcmSeries::findInstance(const TCHAR* key) const
{
  if(key == nullptr) return nullptr;

  unsigned num = m_theInstances.size();
  for(unsigned int i = 0; i < num; ++i)
  {
    CDcmInstance* dcmi = m_theInstances[i];
    
    const TCHAR* dcmiKey = dcmi->getKey();
    if(_tcscmp(dcmiKey, key) == 0) return dcmi;
  }

  return nullptr;
}

DWORD CDcmSeries::removeNotRefInstances()
{
  unsigned num = m_theInstances.size();
  //allocate temp memory
  CDcmInstance** temp = nullptr;
  _TRY_ALLOC(temp, CDcmInstance*[num])
  if(temp == nullptr) return ERROR_NOT_ENOUGH_MEMORY;

  memcpy(temp, m_theInstances.data(), sizeof(CDcmInstance*) * num);
  unsigned numRefInstances = 0;
  for(unsigned i = 0; i < num; i++)
  {
    if(m_theInstances[i]->getRefCount() > 0)
      numRefInstances++;
  }

  _TRY_BEGIN
  m_theInstances.resize(numRefInstances);
  _CATCH_ALL
  _DELETE_ARR(temp);
  return ERROR_NOT_ENOUGH_MEMORY;
  _CATCH_END

  for(unsigned int i = 0, k = 0; i < num && k < numRefInstances; ++i)
  {
    if(temp[i]->getRefCount() > 0)
    {
      m_theInstances[k++] = temp[i];
      temp[i] = nullptr;
    }
  }

  for(unsigned int i = 0; i < num; ++i)
    _DELETE(temp[i]);
  _DELETE_ARR(temp);

  return ERROR_SUCCESS;
}

void CDcmSeries::init()
{
  //ref count
  m_theRefCount = 0;
  //parent
  m_theParent = nullptr;
  //key
  m_theKey = _T("");
  //modality
  m_theModality = _T("");
}

void CDcmSeries::destroy()
{
  removeAllInstances();
}

void CDcmSeries::removeAllInstances()
{
  unsigned num = m_theInstances.size();
  for(unsigned int i = 0; i < num; ++i)
    _DELETE(m_theInstances[i]);
  m_theInstances.clear();
}

DWORD CDcmSeriesProducer::produce(ISeriesInfo& seriesInfo, 
                                  CDcmStudy* parent, 
                                  CDcmSeries*& outSeries)
{
  CDcmSeries* newSeries = nullptr;
  _TRY_ALLOC(newSeries, CDcmSeries);
  if(newSeries == nullptr) return ERROR_NOT_ENOUGH_MEMORY;

  DWORD error = ERROR_SUCCESS;
  
  newSeries->m_theParent = parent;
  newSeries->m_theKey = seriesInfo.getKey();
  newSeries->m_theModality = seriesInfo.getModality();

  //create dcm instance
  int numInstanceInfo = seriesInfo.getNumInstanceInfo();
  if(numInstanceInfo <= 0)
  {
    _DELETE(newSeries);
    return ERROR_INVALID_SERIES_INFO;
  }

  _TRY_BEGIN
  newSeries->m_theInstances.reserve(numInstanceInfo);
  _CATCH_ALL
  _DELETE(newSeries);
  return ERROR_NOT_ENOUGH_MEMORY;
  _CATCH_END
  for(int i = 0; i < numInstanceInfo; ++i)
  {
    IInstanceInfo* instanceInfo = seriesInfo.getInstanceInfo(i);
    if(instanceInfo == nullptr) continue;

    CDcmInstance* ii = nullptr;
    error = CDcmInstanceProducer::produce(*instanceInfo, newSeries, ii);
    if(error != ERROR_SUCCESS)
    {
      _DELETE(newSeries);
      return error;
    }

    newSeries->m_theInstances.push_back(ii);
  }

  if(newSeries->m_theInstances.size() == 0)
  {
    _DELETE(newSeries);
    return ERROR_INVALID_SERIES_INFO;
  }

  outSeries = newSeries;
  return ERROR_SUCCESS;
}
